﻿using ArtMath.Resource;
using System;
using System.ComponentModel;
using System.Drawing;
using ArtMath.Data;
using ArtMath.Setting;
using ArtMath.Core.Helper;
using ArtMath.Attribute;
using ArtMath.Core.Data;
using ArtMath.Component.Line;
using ArtMath.Component.Interface;
using ArtMath.Component.Circle;
using ArtMath.PointCollection;

namespace ArtMath.Component.Point
{
    /// <summary>
    /// 定比分点基类
    /// </summary>
    [Serializable]
    public abstract class ProportionatePointBase : ConstructedPointBase
    {
        PadStringX rate;
        bool movable;
        public ProportionatePointBase(SketchPad pad, string name, ToolTypeName toolType, LineBase line, string rate, bool addToList = true) : base(pad, name, toolType, addToList)
        {
            OutlineColor = Settings.Instance.ProportionatePointOutlineColor;
            FillColor = Settings.Instance.ProportionatePointFillColor;
            OutHosts = new LineBase[1];
            Line = line;
            Ratio = new PadStringX(Pad, rate);
        }
        [DefaultValue(typeof(Color), "75, 78, 42")]
        public override Color OutlineColor
        {
            get
            {
                return base.OutlineColor;
            }

            set
            {
                base.OutlineColor = value;
            }
        }
        [DefaultValue(typeof(Color), "91, 98, 46")]
        public override Color FillColor
        {
            get
            {
                return base.FillColor;
            }

            set
            {
                base.FillColor = value;
            }
        }
        public override bool Movable
        {
            get
            {
                return movable || base.Movable;
            }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("Line")]
        public LineBase Line
        {
            get { return OutHosts[0]; }
            set { SetLine(0, value); }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("Ratio")]
        public virtual PadStringX Ratio
        {
            get { return rate; }
            set
            {
                if (rate is object)
                {
                    rate.ParametersValueChanging -= Ratio_ParametersValueChanging;
                    rate.ParametersValueChanged -= Ratio_ParametersValueChanged;
                    rate.ExpressionSetting -= Ratio_ExpressionSetting;
                    rate.ExpressionSet -= Ratio_ExpressionSet;
                }
                rate = value;
                if (rate is object)
                {
                    rate.ParametersValueChanging += Ratio_ParametersValueChanging;
                    rate.ParametersValueChanged += Ratio_ParametersValueChanged;
                    rate.ExpressionSetting += Ratio_ExpressionSetting;
                    rate.ExpressionSet += Ratio_ExpressionSet;
                }
            }
        }

        void Ratio_ParametersValueChanging(DocStringX sender)
        {
            movable = true;
            Pad.MoveObject_DoMouseDown(this);
        }

        void Ratio_ExpressionSetting(StringX sender)
        {
            movable = true;
            Pad.MoveObject_DoMouseDown(this);
        }

        void Ratio_ParametersValueChanged(DocStringX sender, ParametersValueChangedEventArgs e)
        {
            if (Ratio.Value != -1)
            {
                if (Pad.MoveObject_DoMouseMove(this, GetNewLocationAfterOutHostChanged()))
                {

                }
            }
            Pad.MoveObject_DoMouseUp(this);
            movable = false;
        }
        void Ratio_ExpressionSet(StringX sender, ExpressionSetEventArgs e)
        {
            if (Ratio.Value == -1)
            {
                Pad.ShowMessage(Resources.Translate("RatioCannotBe"), MessageType.Error);
                Ratio.SetExpression(e.OldExpression, false);
            }
            else
            {
                if (Pad.MoveObject_DoMouseMove(this, GetNewLocationAfterOutHostChanged()))
                {

                }
                else
                {
                    Pad.ShowMessage(string.Format(Resources.Translate("FailModify"), OfTranslator("Ratio")), MessageType.Error);
                    Ratio.SetExpression(e.OldExpression, false);
                }
            }
            Pad.MoveObject_DoMouseUp(this);
            movable = false;
        }
        public override PointD GetNewLocationAfterOutHostChanged(bool getXY = false)
        {
            LineSegmentBase lsb = Line as LineSegmentBase;
            if (lsb != null)
            {
                return getXY ? Utility.RatePoint(lsb.Point1.NewXY, lsb.Point2.NewXY, Ratio.Value) :
                    Utility.RatePoint(lsb.Point1.NewPxy, lsb.Point2.NewPxy, Ratio.Value);
            }
            else
            {
                IArc arc = Line as IArc;
                ICircle circle = Line as ICircle;
                if (arc != null && circle != null)
                {
                    PointD xy = circle.NewCenter.Offset(arc.NewStart + arc.NewSweep * Ratio.Value / (1 + Ratio.Value), circle.NewRadius);
                    return getXY ? xy : Pad.XYToPxy(xy);
                }
            }
            return base.GetNewLocationAfterOutHostChanged(getXY);
        }
        public override void ConvertType(ToolTypeName targetType)
        {
            if (targetType != ToolType) return;
            ProportionatePointBase targetPoint = null;
            SimulateDeleted(() =>
            {
                if (Pad.CoordinateType == CoordinateSystemType.PolarCoordinate)
                {
                    targetPoint = new PProportionatePoint(Pad, Name, Line, Ratio.DirectExpression, false);
                }
                else
                {
                    targetPoint = new RProportionatePoint(Pad, Name, Line, Ratio.DirectExpression, false);
                }
            });
            afterGenerateNewType(targetPoint);
        }
    }
}
